using Sustainalytics.Entities;
using Sustainalytics.Utils;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;

namespace Sustainalytics.Portfolios.BL.Model
{
    public class PortfolioSecurityModel : IEquatable<PortfolioSecurityModel>
    {
        public PortfolioSecurityModel()
        {
            AccessDetails = string.Empty;
        }

        public PortfolioSecurityModel(
            Guid id, 
            Guid portfolioId, 
            DisplayInformation displayInfo, 
            MatchedInformation matchedInfo,
            Guid companyId, 
            string companyNameUrlFriendly, 
            string securityId, 
            double? securityWeight)
        {
            Id = id;
            PortfolioId = portfolioId;
            DisplayInfo = displayInfo;
            MatchedInfo = matchedInfo;
            CompanyId = companyId;
            CompanyNameUrlFriendly = companyNameUrlFriendly;
            SecurityId = securityId;
            SecurityWeight = securityWeight;
        }

        public string AccessDetails { get; set; }

        public Guid CompanyId { get; set; }

        public string CompanyNameLowercase { get { return string.IsNullOrEmpty(MatchedInfo.CompanyName) ? string.Empty : MatchedInfo.CompanyName.ToLowerInvariant(); } }

        public string CompanyNameUrlFriendly { get; set; }

        public DisplayInformation DisplayInfo { get; set; }

        public Guid Id { get; set; }

        public bool IsAccesible
        {
            get { return AccessDetails.IsNullOrEmpty(); }
        }

        public MatchedInformation MatchedInfo { get; set; }

        public Guid PortfolioId { get; set; }

        public string SecurityId { get; set; }

        public double? SecurityWeight { get; set; }

        public bool IsInvalidMatch { get; set; }

        public ICollection<int> UniverseIds { get; set; }
        public bool IsValid { get; set; }
        public static bool operator !=(PortfolioSecurityModel left, PortfolioSecurityModel right)
        {
            return !Equals(left, right);
        }

        public static bool operator ==(PortfolioSecurityModel left, PortfolioSecurityModel right)
        {
            return Equals(left, right);
        }

        public void AttachFeatureUniverses(ICollection<int> universeIds)
        {
            UniverseIds = universeIds;
        }

        public bool Equals(PortfolioSecurityModel other)
        {
            if (ReferenceEquals(null, other))
            {
                return false;
            }
            if (ReferenceEquals(this, other))
            {
                return true;
            }
            return CompanyId.Equals(other.CompanyId) && Equals(DisplayInfo, other.DisplayInfo) && Equals(MatchedInfo, other.MatchedInfo) && PortfolioId.Equals(other.PortfolioId) && CompanyNameUrlFriendly==other.CompanyNameUrlFriendly  && SecurityWeight == other.SecurityWeight;
        }

        public override bool Equals(object obj)
        {
            if (ReferenceEquals(null, obj))
            {
                return false;
            }
            if (ReferenceEquals(this, obj))
            {
                return true;
            }
            if (obj.GetType() != this.GetType())
            {
                return false;
            }
            return Equals((PortfolioSecurityModel)obj);
        }

        public override int GetHashCode()
        {
            unchecked
            {
                var hashCode = (AccessDetails != null ? AccessDetails.GetHashCode() : 0);
                hashCode = (hashCode * 397) ^ CompanyId.GetHashCode();
                hashCode = (hashCode * 397) ^ (CompanyNameUrlFriendly != null ? CompanyNameUrlFriendly.GetHashCode() : 0);
                hashCode = (hashCode * 397) ^ (DisplayInfo != null ? DisplayInfo.GetHashCode() : 0);
                hashCode = (hashCode * 397) ^ (MatchedInfo != null ? MatchedInfo.GetHashCode() : 0);
                hashCode = (hashCode * 397) ^ PortfolioId.GetHashCode();
                hashCode = (hashCode * 397) ^ SecurityId.GetHashCode();
                return hashCode;
            }
        }

        public PortfolioDetails GetPortfolioDetails()
        {
            return new PortfolioDetails
            {
                CompanyId = CompanyId,
                CompanyNameLowercase = CompanyNameLowercase,
                CompanyNameUrlFriendly = CompanyNameUrlFriendly,
                DisplayInfo = DisplayInfo,
                Id = Id,
                MatchedInfo = MatchedInfo,
                PortfolioId = PortfolioId,
                SecurityId = SecurityId,
                SecurityWeight = SecurityWeight,
               
            };
        }

        public PortfolioMatches GetPortfolioMatches()
        {
            return new PortfolioMatches
            {
                CompanyId = CompanyId,
                CompanyNameLowercase = CompanyNameLowercase,
                CompanyNameUrlFriendly = CompanyNameUrlFriendly,
                DisplayInfo = DisplayInfo,
                Id = Id,
                MatchedInfo = MatchedInfo,
                PortfolioId = PortfolioId,
                SecurityId = SecurityId,
                SecurityWeight = SecurityWeight,
            };
        }

        public PortfolioUserInput GetPortfolioUserInput(Guid userId)
        {
            return new PortfolioUserInput
            {
                Id = Id,
                InsertDate = DateTime.Today,
                PortfolioId = PortfolioId,
                SecurityIdentifier = DisplayInfo.SecurityIdentifier,
                SecurityName = DisplayInfo.CustomSecurityIdentifierName,
                UserId = userId,
            };
        }

        public PortfolioSecurityModel ValidateAgainstUserUniverses(ICollection<int> accountUniverseIds)
        {

            if (this == new PortfolioSecurityModel.Null(Guid.NewGuid(), Guid.Empty, DisplayInfo.CustomSecurityIdentifierName, DisplayInfo.SecurityIdentifier))
                return this;

            const string noMessage = "No access";

            if (accountUniverseIds == null || UniverseIds == null)
            {
                AccessDetails = noMessage;
                return this;
            }


            if (UniverseIds.Intersect(accountUniverseIds).IsNullOrEmpty())
            {
                AccessDetails = noMessage;

            }
            return this;

        }

        //todo: Madalina:
        //I would rather not use a special class for this but a static method in PortfolioSecurityModel.Null like the way is implemented in Guid.NewGuid(). 
        //Using default parameters would help us have only one method.

        public class Null : PortfolioSecurityModel
        {
            public Null()
                : this(Guid.Empty, Guid.Empty, new DisplayInformation(), new MatchedInformation(), Guid.Empty, string.Empty,string.Empty,-1)
            {
            }

            public Null(Guid id, Guid portfolioId, string securityName, string securityIdentifier)
                : this(id, portfolioId, new DisplayInformation(securityIdentifier, securityName), new MatchedInformation(), Guid.Empty,string.Empty ,string.Empty,-1)
            { }

            internal Null(Guid id, Guid portfolioId, DisplayInformation displayInfo, MatchedInformation matchedInfo, Guid companyId, string companyNameUrlFriendly, string securityId,double securityWeight)
                : base(id, portfolioId, displayInfo, matchedInfo, companyId, companyNameUrlFriendly,securityId,securityWeight)
            {
            }
        }
    }
}